
`define PORT_A	0
`define PORT_B	1

`timescale 1ns / 1ps

module tb_reg_file;

parameter CLK_PERIOD = 10;

parameter DATA_WIDTH 	= 32;
parameter ADDR_WIDTH 	= 5;

reg clk;
reg i_wr_en;
reg	[ADDR_WIDTH-1:0] i_a_addr;
reg [ADDR_WIDTH-1:0] i_b_addr;
reg [DATA_WIDTH-1:0] i_b_data;

wire [DATA_WIDTH-1:0] o_a_data;
wire [DATA_WIDTH-1:0] o_b_data;

defparam reg_file_DUT.DATA_WIDTH = DATA_WIDTH;
defparam reg_file_DUT.ADDR_WIDTH = ADDR_WIDTH;

reg_file reg_file_DUT(
	.clk(clk),
	.i_wr_en(i_wr_en),
	.i_a_addr(i_a_addr),
	.i_b_addr(i_b_addr),
	.i_b_data(i_b_data),
	.o_a_data(o_a_data),
	.o_b_data(o_b_data)
);

initial
begin
	init_all_inputs_to_0;
	#10
	set_all_inputs_and_clock( 1, 2, 1, 20 );
	set_all_inputs_and_clock( 2, 4, 1, 30 );
	set_all_inputs_and_clock( 2, 4, 0, 40 );	
	set_all_inputs_and_clock( 2, 4, 1, 50 );		
	#10
	$finish;
end

always
	#(CLK_PERIOD/2) clk = ~clk;
	
task init_all_inputs_to_0;
begin
	clk = 0;
	i_a_addr = 0;
	i_b_addr = 0;
	i_b_data = 0;
	i_wr_en = 0;
end
endtask

task set_addr;
	input integer port;
	input [ADDR_WIDTH-1:0] addr;
begin
	if( port == `PORT_A ) begin
		i_a_addr = addr;
	end
	else if( port == `PORT_B  ) begin
		i_b_addr = addr;
	end
end
endtask

task set_input_data;
	input [DATA_WIDTH-1:0] val;
begin
	i_b_data = val;
end
endtask

task set_wr_en;
	input wr_en;
begin
	i_wr_en = wr_en;
end
endtask

task set_all_inputs;
	input [ADDR_WIDTH-1:0] addr_a;
	input [ADDR_WIDTH-1:0] addr_b;
	input wr_en;	
	input [DATA_WIDTH-1:0] val;
begin
	set_addr( `PORT_A, addr_a );
	set_addr( `PORT_B, addr_b );
	set_input_data( val );
	set_wr_en( wr_en );
end
endtask

task set_all_inputs_and_clock;
	input [ADDR_WIDTH-1:0] addr_a;
	input [ADDR_WIDTH-1:0] addr_b;
	input wr_en;
	input [DATA_WIDTH-1:0] val;
begin
	set_all_inputs( addr_a, addr_b, wr_en, val );
	#10
	;
end
endtask

endmodule
